var  {global }
   FilterSize: real; {0-100% of image size}
   TransitionWidth: real; {0-100% of filter radius}
    PlotFilter: boolean;

macro 'FFT [F]';
begin
			fft('foreward');
end;


macro 'Abitrary Selection FFT [A]';
var
   pid1, pid2, x, y, w,h, size: integer;
   scale: real;
begin
   GetRoi(x, y, w, h);
   if w = y then begin
      SelectAll;
      GetRoi(x, y, w, h);
   end;
   if w > h then begin
      x := x + (w - h) div 2;
      w := h;
       MakeRoi(x, y, w, h);
   end;
   if h > w then begin
      y := y+ (h - w) div 2;
      h := w;
       MakeRoi(x, y, w, h);
   end;
   size := 2048;
   if w <= 32 then size := 32
   else if w <= 64 then size := 64
   else if w <= 128 then size := 128
   else if w <= 256 then size := 256
   else if w <= 512 then size := 512
   else if w <= 1024 then size := 1024;
   scale := size / w;
   SetScaling('Bilinear; New Window');
   ScaleAndRotate(scale, scale, 0);
   pid1 := pidNumber;
			fft('foreward');
   pid2 := pidNumber;
   SelectPic(pid1);
   dispose;
   SelectPic(pid2);
end;


macro 'Inverse FFT [I]';
begin
			fft('Inverse');
end;


macro 'Inverse FFT with Custom Mask [M]';
var
   w,h, pixWidth, i, nSmooths: integer;
begin
   GetPicSize(w, h);
   GetHistogram(0, 0, w,h);
   if (histogram[0] = 0) and (histogram[255] = 0) then begin
       PutMessage('No mask. You need to edit the power spectrum using black to pass frequencies or white to filter freqwencies.');
       exit;
   end;
   pixWidth := GetNumber('Transition Width in Pixels:', 6, 0);
   nSmooths := pixWidth div 2;
   if histogram[0] <> 0 then
       ChangeValues(1, 255, 255)
   else
       ChangeValues(0, 254, 0);
   for i := 1 to nSmooths do
      filter('smooth more');
			fft('Inverse with Filter');
end;

macro 'Inverse FFT with Filter';
begin
			fft('Inverse with Filter');
end;

{
procedure fftFilter(type: string; percent: integer);
var
   width, height, size, loc: integer;
begin
   if percent < 0 then
      percent := 0;
   if percent > 100 then
      percent := 100;
   SaveState;
			fft('foreward');
   GetPicSize(width, height);
   size := round(( percent/100) * width);
   loc := width div 2 - size/2;
   MakeOvalRoi(loc, loc, size, size);
   if type = 'high' then
      SetForeground(0)
   else
      SetForeground(255);
   Fill;
			fft('Inverse');
   RestoreState;
end;


macro 'High Pass Filter... [H]';
var
   percent: integer;
begin
   percent := GetNumber('Filter size (0-100%):', 10, 0);
   fftFilter('high', percent);
end;

macro 'Low Pass Filter... [L]';
var
   percent: integer;
begin
   percent := GetNumber('Filter size (0-100%):', 20, 0);
   fftFilter('low', percent);
end;
}


procedure MakeFilter(size, tWidth, min, max: real);
var
   width, height, roiSize: integer;
   pixWidth, i, loc, v: integer;
begin
   SaveState;
   if size > 100 then size := 100;
   if size < 0 then size := 0;
   if tWidth > 100 then tWidth := 100;
   if tWidth < 0 then tWidth := 0;
   if min > 100 then min := 100;
   if min < 0 then min := 0;
   if max > 100 then max := 100;
   if max < 0 then max := 0;
   if min > max then min := max;
   GetPicSize(width, height);
   SelectAll;
   size := round(size / 100 * width);
   min := round(min / 100 * 255);
   max := round(max / 100 * 255);
   Setbackground(min);
   Clear;
    roiSize := size;
    pixWidth := round(size div 2 * (tWidth/100));
    if pixWidth < 1 then
       pixWidth := 1;
    for i := 1 to pixWidth do begin
       loc := width div 2 - roiSize/2;
       MakeOvalRoi(loc, loc, roiSize, roiSize);
       v := (max-min)  *  exp(-4.5 *  sqr(1 - i  / pixWidth)) + min; {gaussian shape}
       SetForeground(v);
       Fill;
       roiSize := roiSize - 2;
   end;
   KillRoi;
   RestoreState;
end;


procedure doFilter(filterType: string);
var
   width, height: integer;
begin
   if FilterSize = 0 then
      FilterSize := 20;
   if TransitionWidth = 0 then
      TransitionWidth := 50;
   FilterSize := GetNumber('Filter size (0-100%):', FilterSize, 0);
   TransitionWidth := GetNumber('Transition Width (0-100%):', TransitionWidth, 0);
   if TransitionWidth = 0 then
      TransitionWidth := 0.0001;
			fft('foreward');
   MakeFilter(FilterSize, TransitionWidth, 0, 100);
   if FilterType = 'high' then
      Invert;
   if PlotFilter then begin
      getPicSize(width, height);
      MakeLineRoi(0, height / 2, width, height / 2);
      PlotProfile;
      KillRoi;
   end;
   fft('Inverse with Filter');
end;


macro '(---'; begin end;


macro 'High Pass Filter... [H]';
begin
  doFilter('high');
end;

macro 'Low Pass Filter... [L]';
begin
  doFilter('low');
end;

macro 'Toggle Filter Plotting ... [T]';
begin
  if PlotFilter then begin
      PlotFilter := false;
      PutMessage('Filter profiles will not be plotted.');
  end else begin
      PlotFilter := true;
      PutMessage('Filter profiles will  be plotted.');
  end;
end;


macro '(---'; begin end;


macro 'Autocorrelation';
var
   fft1, fft2: integer;
begin
			fft('foreward');
   fft1 := pidNumber;
   ImageMath('cmul', fft1, fft1, 1, 0, 'FFT2');
   fft2 := pidNumber;
   SelectPic(fft1);
   Dispose;
   SelectPic(fft2);
			fft('Inverse');
   fft('Swap Quadrants');
  SetPicName('Autocorrelation')
end;


macro 'Autocorrelation with Padding';
var
   pad, fft1, fft2: integer;
   width, height: integer;
   n,mean,mode,min,max: real;
begin
   SelectAll;
    Measure;
   GetResults(n,mean,mode,min,max);
   Copy;
   GetPicSize(width, height);
   SetNewSize(width * 2, height * 2);
   Setbackgrount(round(mean));
   MakeNewWindow('Padded Image');
   MakeRoi(0, 0, width, height);
   Paste;
   KillRoi;
   pad := pidNumber;
			fft('foreward');
   fft1 := pidNumber;
   ImageMath('cmul', fft1, fft1, 1, 0, 'FFT2');
   fft2 := pidNumber;
   SelectPic(pad);
   Dispose;
   SelectPic(fft1);
   Dispose;
   SelectPic(fft2);
			fft('Inverse');
   fft('Swap Quadrants');
  SetPicName('Autocorrelation')
end;


macro 'Correlate Two Images' ;
var
   pic1, pic2, fft1, fft2, out: integer;
begin
   if nPics <> 2 then begin
      PutMessage('Exactly two images required.');
      exit;
   end;
   pic1 := pidNumber;
   NextWindow;
   pic2 := pidNumber;
			fft('foreward');
   fft2 := pidNumber;
   SelectPic(pic1);
   fft('foreward');
   fft1 := pidNumber;
   ImageMath('cmul', fft1, fft2, 1, 0, 'FFT2');
   out := pidNumber;
   SelectPic(fft1);
   Dispose;
   SelectPic(fft2);
   Dispose;
   SelectPic(out);
   fft('Inverse');
   fft('Swap Quadrants');
   SetPicName('Correlation');
   SurfacePlot;
end;


macro '(---'; begin end;

macro 'Make Filter...';
var
   width, height: integer;
begin
   if FilterSize = 0 then
      FilterSize := 20;
   if TransitionWidth = 0 then
      TransitionWidth := 50;
   FilterSize := GetNumber('Filter size (0-100%):', FilterSize, 0);
   TransitionWidth := GetNumber('Transition Width (0-100%):', TransitionWidth, 0);
   if TransitionWidth = 0 then
      TransitionWidth := 0.0001;
			Duplicate('Filter');
   MakeFilter(FilterSize, TransitionWidth, 0, 100);
end;


macro 'Redisplay Power Spectrum';
begin
   fft('Display Power Spectrum');
end;

macro 'Swap Quadrants';
begin
   fft('Swap Quadrants');
end;


macro '(---'; begin end;


procedure roi(size: integer);
var
  width, height: integer;
begin
  GetPicSize(width, height);
  if size > width then
     size := width;
  if width = 0 then begin
     PutMessage('No image window open.');
     exit;
  end;
   MakeRoi(width/2 - size/2, height/2 - size/2, size, size);
end;

macro 'Create 32 x 32 selection [1]'; begin roi(32) end;
macro 'Create 64 x 64 selection [2]'; begin roi(64) end;
macro 'Create 128 x 128 selection [3]'; begin roi(128) end;
macro 'Create 256 x 256 selection [4]'; begin roi(256) end;
macro 'Create 512 x 512 selection [5]'; begin roi(512) end;


procedure AnnularSelection(color: integer);
var
  x1,x2,y1,y2,top,left,width,height, w, h:integer;
  xcenter,ycenter,radius1, radius2:integer;
begin
  if pos('FFT',WindowTitle) <> 1 then begin
     beep;
     PutMessage('Frequency domain (FFT) image required.');
     exit;
  end;
  GetPicSize(w,h);
  GetLine(x1,y1,x2,y2,width);
  if x1<0 then begin
     beep;
     PutMessage('Line selection required.');
     exit;
  end;
  SaveState;
  SetForeground(color);
  xcenter:=w/2;
  ycenter:=h/2;
  radius1:=sqrt(sqr(abs(x1-xcenter))+sqr(abs(y1-ycenter)));
  radius2:=sqrt(sqr(abs(x2-xcenter))+sqr(abs(y2-ycenter)));
  if radius1 < radius2 then begin
        MakeOvalROI(xcenter-radius1,ycenter-radius1,radius1*2,radius1*2);
        copy;
        setbackgroundcolor(0);
        MakeOvalROI(xcenter-radius2,ycenter-radius2,radius2*2,radius2*2);
        fill;
        paste;
        killroi;
  end;
  MakeOvalROI(xcenter-radius2,ycenter-radius2,radius2*2,radius2*2);
  copy;
  setbackgroundcolor(0);
  MakeOvalROI(xcenter-radius1,ycenter-radius1,radius1*2,radius1*2);
  fill;
  paste;
  killroi;
  RestoreState;
end;

macro '(---'; begin end;

{The annular selection macros are designed to be used in the power
spectrum window. Using the  line selection tool, a line is drawn that
extends through some range of spatial frequencies. This line should be radial
from the center of the window since the selection will be from the central to
distal portion of the line. After making the line selection, typing W will
cause a black annular selection to be made. Following this selection with the
Inverse command from the FFT macros will result in passing the range of
frequencies selected in the inverse transform. If you want to use the selection
as a notch filter, then type W to create a white annular selection.}

macro 'Black Annular Selection - Pass [B]';
begin
   AnnularSelection(255);
end;

macro 'White Annular Selection - Notch [W]';
begin
   AnnularSelection(0);
end;




